﻿using System;
using System.Collections;

namespace OptimalisationFramework.Utilities.Graphs
{
    class Vertex<Identification, Data, Weight> : IEnumerable
    {
        private Identification id;
        private Data d;
        private Hashtable neighbours;


        public Vertex(Identification id, Data d)
        {
            this.id = id;
            this.d = d;
            neighbours = new Hashtable();
        }

        public int EdgeSize
        {
            get { return neighbours.Count; }
        }

        public Data D
        {
            get { return d; }
        }
        public Identification EdgeEnd(int i)
        {
                ArrayList a = new ArrayList();
                a.AddRange(neighbours.Keys);
                return (Identification)((Edge<Identification, Data,Weight>)neighbours[a[i]]).End;

        }

        public Identification ID
        {
            get { return id; }
        }


        public void AddNeighbour(Identification end, Weight w)
        {
            if (!NeighbourExists(end))
            {
                neighbours.Add(end, new Edge<Identification, Data, Weight>(id, end, w));
            }
        }

        public void RemoveNeighbour(Identification end)
        {
            if (NeighbourExists(end))
            {
                neighbours.Remove(end);
            }
        }

        public Edge<Identification, Data, Weight> GetEdge(Identification end)
        {
            if (NeighbourExists(end))
            {
                return (Edge<Identification, Data, Weight>)neighbours[end];
            }
            return null;
        }

        public bool NeighbourExists(Identification id)
        {
            return neighbours.ContainsKey(id);
        }

        public string Neighbours()
        {
            string n = "";
            foreach (DictionaryEntry e in neighbours)
            {
                Edge<Identification, Data, Weight> k = (Edge<Identification, Data, Weight>)e.Value;
                n += k.End.ToString() + " ";
            }
            return n;
        }

        public override string ToString()
        {
            return "Id: " + id;
        }


        /*
         * Enumerator
         * */
        public IEnumerator GetEnumerator()
        {
            return new VertexEnumerator<Identification, Data, Weight>(this);
        }

        internal Hashtable Edges
        {
            get
            {
                return (neighbours);
            }
        }

        /*
         * Indexer
         * */
        public Edge<Identification, Data, Weight> this[int index]
        {
            get
            {
                ICollection keys = neighbours.Values;
                IEnumerator ie = keys.GetEnumerator();
                ie.Reset();
                int i = 0;
                ie.MoveNext();
                while (ie.MoveNext())
                {
                    if (i == index)
                    {
                        return (Edge<Identification, Data, Weight>)ie.Current;
                    }
                    i++;
                }
                return null;
            }
            /*
            set
            {
                data[index] = value;
            }
             */
        }
    }

    public class VertexEnumerator<Identification, Data, Weight> : IEnumerator
    {
        private Vertex<Identification, Data, Weight> v;
        private IEnumerator ie;

        internal VertexEnumerator(Vertex<Identification, Data, Weight> v)
        {
            this.v = v;
            ie = v.Edges.GetEnumerator();
            ie.Reset();
        }

        public bool MoveNext()
        {
            return ie.MoveNext();
        }

        public object Current
        {
            get
            {
                DictionaryEntry di = (DictionaryEntry)ie.Current;
                return di.Value;
            }
        }

        public void Reset()
        {
            ie.Reset();
        }
    }
}
